<template>
	<div>
		<div class="cell" :style="{ 'background': config.config.property.bgColor }">
			<div class="cell-tool">

				<div class="bk-button-group">
					<el-select v-model="value" @change="handleChange" style="width: 240px">
						<el-option-group v-for="group in sceneoptions" :key="group.label" :label="group.label">
							<el-option v-for="item in group.options" :key="item.label" :label="item.label"
								:value="item.value" />
						</el-option-group>
					</el-select>
					<ul class="btnSplitScreen">
						<li @click="cellCountclick(1)" :class="{ active: isActive, inactive: !isActive }"></li>
						<li @click="cellCountclick(4)" :class="{ factive: fisActive, finactive: !fisActive }"></li>
						<li @click="cellCountclick(9)" :class="{ nactive: nisActive, ninactive: !nisActive }"></li>
						<li @click="cellCountclick(16)" :class="{ txactive: txisActive, txinactive: !txisActive }"></li>
						<li @click="fullScreen" class="screen"></li>
						<li @click="savesceneclick" class="savescene"></li>
					</ul>
					<!-- <button @click="cellCountclick(1)" size="small">1</button>
				<button @click="cellCountclick(4)" size="small">4</button>
				<button @click="cellCountclick(9)" size="small">9</button>
				<button @click="cellCountclick(16)" size="small">16</button> -->
				</div>
			</div>
			<div class="videobox" ref="fullscreenContainer">
				<img class="cancel" v-if="activecancel" @click="fullScreen" src="./image/qxqp.png" alt="" />
				<div class="cell-player">
					<!-- <div :class="cellClass(i)" v-for="i in cellCount" :key="i"-->
					<div :class="activeClass" v-for="i in cellCount" :key="i" style="background: #000;"
						@click="videoactive(i)">
						<video :id="i" controls></video>
						<div class="bottomtitle" :style="{ 'background': config.config.property.bottomtitle }">
							<span>{{ i }}</span>
							<span>{{ videotitle[i-1].name }}</span>
							<span @click="toggleFullScreen(i)">
								<img src="./image/qp.png" alt="" />
							</span>
						</div>
						<!-- <video :id="'video'+i" controls style="width: 100%;height: 100%;background: #fff;"></video> -->
						<!-- <video style="width: 100%; height: 100%; object-fit: fill" ref="videoElement" controls></video> -->
					</div>
				</div>
			</div>
		</div>
		<el-dialog title="保存场景" v-model="dialogFormVisible" width="400px">
			<div style="margin-top: 20px;margin-bottom: 30px;">
				<el-input v-model="savesceneName" placeholder="请输要保存的场景名称"></el-input>
			</div>
			<div slot="footer" class="dialog-footer" style="text-align: center;">
				<el-button @click="dialogFormVisible = false">取 消</el-button>
				<el-button type="primary" @click="sureScene">确 定</el-button>
			</div>
		</el-dialog>
	</div>
</template>
<script>
	import flvjs from 'flv.js'
	import chartBase from '@/mixin/chart-base.js'
	import emitComponentBase from '@/mixin/emit-component-base.js'
	import dataModel from '@/models/panel-config-data.js'
	import {
		checkNegative
	} from '@/utils/util'
	import {
		mapState
	} from 'vuex'
	import config from './config/config'
	import {
		getOptimizedConfig
	} from './config/video-config'
	// import HwCellPlayer from './HwCellPlayer.vue'

	export default {
		name: 'videoPlayback',
		components: {
			// HwCellPlayer
		},
		mixins: [chartBase, emitComponentBase],
		props: ['pareentId', 'widgetId', 'widgetInstanceId', 'widgetName', 'identifier', 'layout', 'w', 'h', 'Item'],
		data() {
			const optimizedConfig = getOptimizedConfig()

			return {
				isActive: true,
				fisActive: true,
				nisActive: true,
				txisActive: true,
				activecancel: false,
				isLoading: false,
				showVisible: false,
				isFull: false,
				dialogFormVisible: false,
				savesceneName: '',
				cellCount: 4,
				videoaction: 1,
				videourlindex: 0,
				videolink: [],
				scenedata: [
					{
							label: 1,
							options: []
						}, {
							label: 4,
							options: []
						}, {
							label: 9,
							options: []
						}, {
							label: 16,
							options: []
						}
				],
				data1: [],
				data4: [],
				data9: [],
				data16: [],
				sceneoptions: [],
				value: '',
				videosrc: [{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
					{
						src: '',
					},
				],
				nameindex: 0,
				videotitle: [{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					},
					{
						name: '',
					}, {
						name: '',
					},
				],
				videoElement: [],
				activeClass: '',
				flvPlayer: null,
				lastDecodedFrames: undefined,
				lastVideoUrl: '', // 保存上次的URL用于重连
				flvPlayers: [], // 多窗口 flvPlayer 实例
				lastVideoUrls: [],
				lastDecodedFramesArr: [],
				// 使用优化配置
				reconnectConfig: {
					maxReconnectAttempts: optimizedConfig.reconnect.maxReconnectAttempts,
					baseDelay: optimizedConfig.reconnect.baseDelay,
					maxDelay: optimizedConfig.reconnect.maxDelay,
					frameCheckInterval: optimizedConfig.reconnect.frameCheckInterval,
					consecutiveFrameStallsThreshold: optimizedConfig.reconnect.consecutiveFrameStallsThreshold,
					reconnectAttempts: [], // 每个播放器的重连次数
					reconnectTimers: [], // 重连定时器
					isReconnecting: [], // 是否正在重连
					lastFrameCheckTime: [], // 上次帧数检查时间
					consecutiveFrameStalls: [], // 连续帧数停滞次数
				},
				// 性能监控配置
				performanceConfig: {
					enableMonitoring: optimizedConfig.performance.enableMonitoring,
					monitorInterval: optimizedConfig.performance.monitorInterval,
					maxStatsRecords: optimizedConfig.performance.maxStatsRecords,
					memoryWarningThreshold: optimizedConfig.performance.memoryWarningThreshold,
					reconnectWarningThreshold: optimizedConfig.performance.reconnectWarningThreshold,
					monitorTimer: null, // 监控定时器
					performanceStats: [], // 性能统计
				},
				// 播放器配置
				playerConfig: optimizedConfig.player,
				// 调试配置
				debugConfig: optimizedConfig.debug,
			}
		},
		computed: {
			...mapState({}),
			cellClass() {
				return function(index) {
					switch (this.cellCount) {
						case 1:
							return ['cell-player-1']
						case 4:
							return ['cell-player-4']
						case 9:
							return ['cell-player-9']
						case 16:
							return ['cell-player-16']
						default:
							break
					}
				}
			},
		},
		watch: {},
		created() {
			this.orgConfig = config
			this.config = JSON.parse(JSON.stringify(this.orgConfig))
			this.chartId = `${this.widgetInstanceId}_01`
		},
		mounted() {
			if (window.isLocalEnv) {
				this.loadWidget()
			}
			this.sceneoptions = JSON.parse(localStorage.getItem("video"))
			
			console.log(this.videosrc.length)
			if (this.cellCount == 1) {
				this.activeClass = 'cell-player-1'
				this.isActive = !this.isActive
				this.fisActive = true
				this.nisActive = true
				this.txisActive = true
			} else if (this.cellCount == 4) {
				this.activeClass = 'cell-player-4'
				this.fisActive = !this.fisActive
				this.isActive = true
				this.nisActive = true
				this.txisActive = true
			} else if (this.cellCount == 9) {
				this.activeClass = 'cell-player-9'
				this.nisActive = !this.nisActive
				this.isActive = true
				this.fisActive = true
				this.txisActive = true
			} else if (this.cellCount == 16) {
				this.activeClass = 'cell-player-16'
				this.txisActive = !this.txisActive
				this.isActive = true
				this.fisActive = true
				this.nisActive = true
			}

			// 添加网络状态监听
			this.handleOnline = this.handleNetworkChange.bind(this)
			this.handleOffline = this.handleNetworkChange.bind(this)
			window.addEventListener('online', this.handleOnline)
			window.addEventListener('offline', this.handleOffline)

			// 启动性能监控
			if (this.performanceConfig.enableMonitoring) {
				this.startPerformanceMonitoring()
			}




		},
		beforeDestroy() {
			// 移除网络状态监听
			window.removeEventListener('online', this.handleOnline)
			window.removeEventListener('offline', this.handleOffline)

			// 清理所有播放器和重连定时器
			for (let i = 0; i < this.flvPlayers.length; i++) {
				this.destroyPlayer(i)
			}

			// 清理所有重连定时器
			this.reconnectConfig.reconnectTimers.forEach(timer => {
				if (timer) {
					clearTimeout(timer)
				}
			})

			// 重置重连配置
			this.reconnectConfig.reconnectAttempts = []
			this.reconnectConfig.reconnectTimers = []
			this.reconnectConfig.isReconnecting = []
			this.reconnectConfig.lastFrameCheckTime = []
			this.reconnectConfig.consecutiveFrameStalls = []

			// 停止性能监控
			if (this.performanceConfig.monitorTimer) {
				clearInterval(this.performanceConfig.monitorTimer)
				this.performanceConfig.monitorTimer = null
			}
		},
		methods: {
			toggleFullScreen(data) {
				const video = document.getElementById(data)
				if (!document.fullscreenElement) {
					if (video.requestFullscreen) {
						video.requestFullscreen() // 标准方法
					} else if (video.mozRequestFullScreen) {
						/* Firefox */
						video.mozRequestFullScreen()
					} else if (video.webkitRequestFullscreen) {
						/* Chrome, Safari & Opera */
						video.webkitRequestFullscreen()
					} else if (video.msRequestFullscreen) {
						/* IE/Edge */
						video.msRequestFullscreen()
					}
				} else {
					if (document.exitFullscreen) {
						document.exitFullscreen() // 标准方法
					} else if (document.mozCancelFullScreen) {
						/* Firefox */
						document.mozCancelFullScreen()
					} else if (document.webkitExitFullscreen) {
						/* Chrome, Safari and Opera */
						document.webkitExitFullscreen()
					} else if (document.msExitFullscreen) {
						/* IE/Edge */
						document.msExitFullscreen()
					}
				}
			},
			// 初始加载时 以及 编排面更改配置时 触发
			loadWidget(pageStatus) {
				this.pageStatus = pageStatus
				this.updateConfigProperty()
				this.updateConfigData()
				if (window.isLocalEnv || this.emitComponentStatus) {
					this.updateParams(pageStatus)
					if (!this.isRealTime) {
						this.debounceGetData()
					}
				}
				this.afterLoadWidget()
				this.checkNegative(this.apiResult)
			},
			cellCountclick(data) {
				this.videoaction = 1
				this.videourlindex = 0
				this.videosrc.map((item, index) => {
					item.src = ''
					this.destroyPlayer(index)
				})
				this.videotitle.map(item => {
					item.name = ''
				})
				if (data == 1) {
					this.isActive = !this.isActive
					this.fisActive = true
					this.nisActive = true
					this.txisActive = true
					this.activeClass = 'cell-player-1'
				}
				if (data == 4) {
					this.fisActive = !this.fisActive
					this.isActive = true
					this.nisActive = true
					this.txisActive = true
					this.activeClass = 'cell-player-4'
				}
				if (data == 9) {
					this.nisActive = !this.nisActive
					this.isActive = true
					this.fisActive = true
					this.txisActive = true
					this.activeClass = 'cell-player-9'
				}
				if (data == 16) {
					this.txisActive = !this.txisActive
					this.isActive = true
					this.fisActive = true
					this.nisActive = true
					this.activeClass = 'cell-player-16'
				}
				this.cellCount = data

				// 切换分屏时，销毁多余的播放器并重置重连状态
				for (let i = data; i < this.flvPlayers.length; i++) {
					this.destroyPlayer(i)
					// 重置重连状态
					this.reconnectConfig.reconnectAttempts[i] = 0
					this.reconnectConfig.consecutiveFrameStalls[i] = 0
					this.reconnectConfig.lastFrameCheckTime[i] = Date.now()
				}
			},
			fullScreen() {
				const elem = this.$refs.fullscreenContainer;
				this.activecancel = !this.activecancel
				if (!document.fullscreenElement) {
					if (elem.requestFullscreen) {
						elem.requestFullscreen();
					} else if (elem.mozRequestFullScreen) {
						/* Firefox */
						elem.mozRequestFullScreen();
					} else if (elem.webkitRequestFullscreen) {
						/* Chrome, Safari & Opera */
						elem.webkitRequestFullscreen();
					} else if (elem.msRequestFullscreen) {
						/* IE/Edge */
						elem.msRequestFullscreen();
					}
				} else {
					if (document.exitFullscreen) {
						document.exitFullscreen();
					} else if (document.mozCancelFullScreen) {
						/* Firefox */
						document.mozCancelFullScreen();
					} else if (document.webkitExitFullscreen) {
						/* Chrome, Safari and Opera */
						document.webkitExitFullscreen();
					} else if (document.msExitFullscreen) {
						/* IE/Edge */
						document.msExitFullscreen();
					}
				}
			},
			savesceneclick() {
				console.log('1111111111', this.videolink)
				// localStorage.setItem('video', JSON.stringify(this.videolink))
				this.dialogFormVisible = true
				// localStorage.getItem("key");


			},
			sureScene() {
				if (this.cellCount == 1) {
					let obj = {
						label: this.savesceneName,
						value: this.videolink
					}
					this.data1.push(obj)
				}
				if (this.cellCount == 4) {
					let obj = {
						label: this.savesceneName,
						value: this.videolink
					}
					this.data4.push(obj)
				}
				if (this.cellCount == 9) {
					let obj = {
						label: this.savesceneName,
						value: this.videolink
					}
					this.data9.push(obj)
				}
				if (this.cellCount == 16) {
					let obj = {
						label: this.savesceneName,
						value: this.videolink
					}
					this.data16.push(obj)
				}
				localStorage.setItem('video', JSON.stringify(this.scenedata))
				let videodata = JSON.parse(localStorage.getItem("video"))
				
				videodata[0].options = this.data1
				videodata[1].options = this.data4
				videodata[2].options = this.data9
				videodata[3].options = this.data16
				localStorage.removeItem("video");
				localStorage.setItem('video', JSON.stringify(videodata))
				this.dialogFormVisible = false
				this.sceneoptions = JSON.parse(localStorage.getItem("video"))
			},
			handleChange(value) {
				console.log('1111111',value)
				if(value.length==1){
					this.cellCount = 1
					this.cellCountclick(1)
				}
				if(value.length>1&&value.length<=4){
					this.cellCount = 4
					this.cellCountclick(4)
				}
				if(value.length>4&&value.length<=9){
					this.cellCount = 9
					this.cellCountclick(9)
				}
				if(value.length>9&&value.length<=16){
					this.cellCount = 16
					this.cellCountclick(16)
				}
				value.map((item,index)=>{
						if (this.cellCount == 1) {
							let srcindex = index
							this.nameindex = srcindex
							this.videotitle.map((item, index) => {
								if (index != srcindex) {
									item.name = ''
								}
							})
						
							this.videotitle[srcindex].name = item.ChannelName
							this.videosrc[srcindex].src = item.WS_FLV || item.FLV
						
						
							if (this.videosrc[srcindex].src.startsWith('http://')) {
								let urlObj = new URL(this.videosrc[srcindex].src)
								this.videosrc[srcindex].src = this.config.config.property.input + urlObj.pathname
							} else {
								this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace('ws://10.0.96.4',
									'wss://10.0.96.4:38443')
							}
							this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
							const videoElement = document.getElementById(this.videoaction)
							this.destroyPlayer(srcindex) // 先销毁旧的
							this.flvPlayers[srcindex] = flvjs.createPlayer({
									type: 'flv',
									isLive: true,
									hasAudio: false,
									url: this.videosrc[srcindex].src,
								},
								this.playerConfig,
							)
							this.flvPlayers[srcindex].attachMediaElement(videoElement)
							this.flvPlayers[srcindex].load()
							try {
								const playPromise = this.flvPlayers[srcindex].play()
								if (playPromise && playPromise.catch) {
									playPromise.catch(e => {
										console.warn('play() error:', e)
									})
								}
							} catch (e) {
								console.warn('play() error:', e)
							}
							this.listenVideo(srcindex)
							// document.getElementById(this.videoaction).style.border = 'none'
						}
						if (this.cellCount == 4) {
							// this.videosrc.length = 4
							// const emptyIndex = this.videosrc.findIndex((item, index) => item.src === '')
							
							const emptyIndex = this.videourlindex
							if (emptyIndex !== -1) {
								let srcindex = emptyIndex
								this.nameindex = srcindex
								this.videotitle[srcindex].name = item.ChannelName
								this.videosrc[srcindex].src = item.WS_FLV || item.FLV
						
						
								if (this.videosrc[srcindex].src.startsWith('http://')) {
									let urlObj = new URL(this.videosrc[srcindex].src)
									this.videosrc[srcindex].src = this.config.config.property.input + urlObj
										.pathname
								} else {
									this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace(
										'ws://10.0.96.4',
										'wss://10.0.96.4:38443')
								}
								this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
								const videoElement = document.getElementById(srcindex + 1)
								this.destroyPlayer(srcindex) // 先销毁旧的
								this.flvPlayers[srcindex] = flvjs.createPlayer({
										type: 'flv',
										isLive: true,
										hasAudio: false,
										url: this.videosrc[srcindex].src,
									},
									this.playerConfig,
								)
								this.flvPlayers[srcindex].attachMediaElement(videoElement)
								this.flvPlayers[srcindex].load()
								try {
									const playPromise = this.flvPlayers[srcindex].play()
									if (playPromise && playPromise.catch) {
										playPromise.catch(e => {
											console.warn('play() error:', e)
										})
									}
								} catch (e) {
									console.warn('play() error:', e)
								}
								this.listenVideo(srcindex)
								let number = this.videourlindex + 1
								this.videourlindex = number
								// document.getElementById(srcindex + 1).style.border = 'none'
							}
						}
						if (this.cellCount == 9) {
							// this.videosrc.length = 4
							const emptyIndex = this.videourlindex
							if (emptyIndex !== -1) {
								let srcindex = emptyIndex
								this.nameindex = srcindex
								this.videotitle[srcindex].name = item.ChannelName
								this.videosrc[srcindex].src = item.WS_FLV || item.FLV
						
						
								if (this.videosrc[srcindex].src.startsWith('http://')) {
									let urlObj = new URL(this.videosrc[srcindex].src)
									this.videosrc[srcindex].src = this.config.config.property.input + urlObj
										.pathname
								} else {
									this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace(
										'ws://10.0.96.4',
										'wss://10.0.96.4:38443')
								}
								this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
								const videoElement = document.getElementById(srcindex + 1)
								this.destroyPlayer(srcindex) // 先销毁旧的
								this.flvPlayers[srcindex] = flvjs.createPlayer({
										type: 'flv',
										isLive: true,
										hasAudio: false,
										url: this.videosrc[srcindex].src,
									},
									this.playerConfig,
								)
								this.flvPlayers[srcindex].attachMediaElement(videoElement)
								this.flvPlayers[srcindex].load()
								try {
									const playPromise = this.flvPlayers[srcindex].play()
									if (playPromise && playPromise.catch) {
										playPromise.catch(e => {
											console.warn('play() error:', e)
										})
									}
								} catch (e) {
									console.warn('play() error:', e)
								}
								this.listenVideo(srcindex)
								let number = this.videourlindex + 1
								this.videourlindex = number
								// document.getElementById(srcindex + 1).style.border = 'none'
							}
						}
						if (this.cellCount == 16) {
							// this.videosrc.length = 4
							const emptyIndex = this.videourlindex
							if (emptyIndex !== -1) {
								let srcindex = emptyIndex
								this.nameindex = srcindex
								this.videotitle[srcindex].name = item.ChannelName
								this.videosrc[srcindex].src = item.WS_FLV || item.FLV
						
						
								if (this.videosrc[srcindex].src.startsWith('http://')) {
									let urlObj = new URL(this.videosrc[srcindex].src)
									this.videosrc[srcindex].src = this.config.config.property.input + urlObj
										.pathname
								} else {
									this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace(
										'ws://10.0.96.4',
										'wss://10.0.96.4:38443')
								}
								this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
								const videoElement = document.getElementById(srcindex + 1)
								this.destroyPlayer(srcindex) // 先销毁旧的
								this.flvPlayers[srcindex] = flvjs.createPlayer({
										type: 'flv',
										isLive: true,
										hasAudio: false,
										url: this.videosrc[srcindex].src,
									},
									this.playerConfig,
								)
								this.flvPlayers[srcindex].attachMediaElement(videoElement)
								this.flvPlayers[srcindex].load()
								try {
									const playPromise = this.flvPlayers[srcindex].play()
									if (playPromise && playPromise.catch) {
										playPromise.catch(e => {
											console.warn('play() error:', e)
										})
									}
								} catch (e) {
									console.warn('play() error:', e)
								}
								this.listenVideo(srcindex)
								let number = this.videourlindex + 1
								this.videourlindex = number
								// document.getElementById(srcindex + 1).style.border = 'none'
							}
						}
					
				})
			},

			videoactive(i) {
				// if (i != this.videoaction && this.videoaction != 0) {
				// 	document.getElementById(this.videoaction).style.border = 'none'
				// 	this.videoaction = i
				// 	console.log(i)
				// 	document.getElementById(this.videoaction).style.border = '1px solid red'
				// } else {
				// 	this.videoaction = i
				// 	console.log(i)
				// 	document.getElementById(this.videoaction).style.border = '1px solid red'
				// }
			},
			// 接收xvue发来的实时数据
			handleRealTimeCommunication(realTimeData) {
				if (this.config.config.property.isDebounce && this.isStopRealData) {
					return
				}

				const result = this.getResult(realTimeData)
				if (this.isNoData || this.autoRefreshIsSameRes(result)) {
					this.isLoading = false
					return
				}
				const {
					data,
					property
				} = this.config.config

				// api请求，拿到数据
				if (data.dataSourceType !== 'xMinerRedisRealTime') {
					this.getCorrectParams(this.params, data.dataSourceType) // 参数存入xvue，导出数据时使用
				}
			},
			acceptEvtMsg(paramters, key, obj) {
				this.checkUpdateParams(obj)
			},
			checkUpdateParams(obj) {
				console.log('接收到的数据', obj)
				const _obj = obj || {}
				let oo = {}
				let flag = false
				for (const key in _obj) {
					if (key.indexOf('emit_params_obj') > -1) {
						const o = _obj[key]
						if (o.eventKey) {
							const event = this.config.events.find(e => e.type === 'in' && e.key === o.eventKey)
							if (event) {
								flag = true
								oo = o
							}
							break
						}
					}
				}
				if (flag) {
					let objdata = oo?.parameters[oo?.keys[0]]
					let httpdata = {
						serial: objdata.serial,
						code: objdata.code,
					}
					fetch(this.config.config.property.input + '/api/v1/stream/start', {
							method: 'POST',
							headers: {
								'Content-Type': 'application/json',
							},
							body: JSON.stringify(httpdata),
						})
						.then(response => response.json())
						.then(data => {
							console.log(data)

							if (this.cellCount == 1) {
								let srcindex = Number(this.videoaction) - 1
								this.nameindex = srcindex
								this.videotitle.map((item, index) => {
									if (index != srcindex) {
										item.name = ''
									}
								})

								this.videotitle[srcindex].name = data.ChannelName
								this.videosrc[srcindex].src = data.WS_FLV || data.FLV

								this.videolink[srcindex] = data

								if (this.videosrc[srcindex].src.startsWith('http://')) {
									let urlObj = new URL(this.videosrc[srcindex].src)
									this.videosrc[srcindex].src = this.config.config.property.input + urlObj.pathname
								} else {
									this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace('ws://10.0.96.4',
										'wss://10.0.96.4:38443')
								}
								this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
								const videoElement = document.getElementById(this.videoaction)
								this.destroyPlayer(srcindex) // 先销毁旧的
								this.flvPlayers[srcindex] = flvjs.createPlayer({
										type: 'flv',
										isLive: true,
										hasAudio: false,
										url: this.videosrc[srcindex].src,
									},
									this.playerConfig,
								)
								this.flvPlayers[srcindex].attachMediaElement(videoElement)
								this.flvPlayers[srcindex].load()
								try {
									const playPromise = this.flvPlayers[srcindex].play()
									if (playPromise && playPromise.catch) {
										playPromise.catch(e => {
											console.warn('play() error:', e)
										})
									}
								} catch (e) {
									console.warn('play() error:', e)
								}
								this.listenVideo(srcindex)
								// document.getElementById(this.videoaction).style.border = 'none'
							}
							if (this.cellCount == 4) {
								// this.videosrc.length = 4
								// const emptyIndex = this.videosrc.findIndex((item, index) => item.src === '')
								console.log(this.videourlindex)
								if (this.videourlindex > 3) {
									this.videourlindex = 0
								}
								const emptyIndex = this.videourlindex
								if (emptyIndex !== -1) {
									let srcindex = emptyIndex
									this.nameindex = srcindex
									this.videotitle[srcindex].name = data.ChannelName
									this.videosrc[srcindex].src = data.WS_FLV || data.FLV

									this.videolink[srcindex] = data

									if (this.videosrc[srcindex].src.startsWith('http://')) {
										let urlObj = new URL(this.videosrc[srcindex].src)
										this.videosrc[srcindex].src = this.config.config.property.input + urlObj
											.pathname
									} else {
										this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace(
											'ws://10.0.96.4',
											'wss://10.0.96.4:38443')
									}
									this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
									const videoElement = document.getElementById(srcindex + 1)
									this.destroyPlayer(srcindex) // 先销毁旧的
									this.flvPlayers[srcindex] = flvjs.createPlayer({
											type: 'flv',
											isLive: true,
											hasAudio: false,
											url: this.videosrc[srcindex].src,
										},
										this.playerConfig,
									)
									this.flvPlayers[srcindex].attachMediaElement(videoElement)
									this.flvPlayers[srcindex].load()
									try {
										const playPromise = this.flvPlayers[srcindex].play()
										if (playPromise && playPromise.catch) {
											playPromise.catch(e => {
												console.warn('play() error:', e)
											})
										}
									} catch (e) {
										console.warn('play() error:', e)
									}
									this.listenVideo(srcindex)
									let number = this.videourlindex + 1
									this.videourlindex = number
									// document.getElementById(srcindex + 1).style.border = 'none'
								}
							}
							if (this.cellCount == 9) {
								if (this.videourlindex > 8) {
									this.videourlindex = 0
								}
								// this.videosrc.length = 4
								const emptyIndex = this.videourlindex
								if (emptyIndex !== -1) {
									let srcindex = emptyIndex
									this.nameindex = srcindex
									this.videotitle[srcindex].name = data.ChannelName
									this.videosrc[srcindex].src = data.WS_FLV || data.FLV

									this.videolink[srcindex] = data

									if (this.videosrc[srcindex].src.startsWith('http://')) {
										let urlObj = new URL(this.videosrc[srcindex].src)
										this.videosrc[srcindex].src = this.config.config.property.input + urlObj
											.pathname
									} else {
										this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace(
											'ws://10.0.96.4',
											'wss://10.0.96.4:38443')
									}
									this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
									const videoElement = document.getElementById(srcindex + 1)
									this.destroyPlayer(srcindex) // 先销毁旧的
									this.flvPlayers[srcindex] = flvjs.createPlayer({
											type: 'flv',
											isLive: true,
											hasAudio: false,
											url: this.videosrc[srcindex].src,
										},
										this.playerConfig,
									)
									this.flvPlayers[srcindex].attachMediaElement(videoElement)
									this.flvPlayers[srcindex].load()
									try {
										const playPromise = this.flvPlayers[srcindex].play()
										if (playPromise && playPromise.catch) {
											playPromise.catch(e => {
												console.warn('play() error:', e)
											})
										}
									} catch (e) {
										console.warn('play() error:', e)
									}
									this.listenVideo(srcindex)
									let number = this.videourlindex + 1
									this.videourlindex = number
									// document.getElementById(srcindex + 1).style.border = 'none'
								}
							}
							if (this.cellCount == 16) {
								if (this.videourlindex > 15) {
									this.videourlindex = 0
								}
								// this.videosrc.length = 4
								const emptyIndex = this.videourlindex
								if (emptyIndex !== -1) {
									let srcindex = emptyIndex
									this.nameindex = srcindex
									this.videotitle[srcindex].name = data.ChannelName
									this.videosrc[srcindex].src = data.WS_FLV || data.FLV

									this.videolink[srcindex] = data

									if (this.videosrc[srcindex].src.startsWith('http://')) {
										let urlObj = new URL(this.videosrc[srcindex].src)
										this.videosrc[srcindex].src = this.config.config.property.input + urlObj
											.pathname
									} else {
										this.videosrc[srcindex].src = this.videosrc[srcindex].src.replace(
											'ws://10.0.96.4',
											'wss://10.0.96.4:38443')
									}
									this.lastVideoUrls[srcindex] = this.videosrc[srcindex].src
									const videoElement = document.getElementById(srcindex + 1)
									this.destroyPlayer(srcindex) // 先销毁旧的
									this.flvPlayers[srcindex] = flvjs.createPlayer({
											type: 'flv',
											isLive: true,
											hasAudio: false,
											url: this.videosrc[srcindex].src,
										},
										this.playerConfig,
									)
									this.flvPlayers[srcindex].attachMediaElement(videoElement)
									this.flvPlayers[srcindex].load()
									try {
										const playPromise = this.flvPlayers[srcindex].play()
										if (playPromise && playPromise.catch) {
											playPromise.catch(e => {
												console.warn('play() error:', e)
											})
										}
									} catch (e) {
										console.warn('play() error:', e)
									}
									this.listenVideo(srcindex)
									let number = this.videourlindex + 1
									this.videourlindex = number
									// document.getElementById(srcindex + 1).style.border = 'none'
								}
							}
						})
						.catch(error => console.error('Error:', error))
				}
			},
			destroyPlayer(index) {
				if (this.flvPlayers[index]) {
					try {
						this.flvPlayers[index].pause()
					} catch (e) {}
					try {
						this.flvPlayers[index].unload()
					} catch (e) {}
					try {
						this.flvPlayers[index].detachMediaElement()
					} catch (e) {}
					try {
						this.flvPlayers[index].destroy()
					} catch (e) {}
					this.flvPlayers[index] = null
				}

				// 清理重连相关状态
				if (this.reconnectConfig.reconnectTimers[index]) {
					clearTimeout(this.reconnectConfig.reconnectTimers[index])
					this.reconnectConfig.reconnectTimers[index] = null
				}
				this.reconnectConfig.isReconnecting[index] = false
			},

			listenVideo(index) {
				const that = this
				if (!this.flvPlayers[index]) return

				// 初始化重连配置
				if (this.reconnectConfig.reconnectAttempts[index] === undefined) {
					this.reconnectConfig.reconnectAttempts[index] = 0
					this.reconnectConfig.isReconnecting[index] = false
					this.reconnectConfig.lastFrameCheckTime[index] = Date.now()
					this.reconnectConfig.consecutiveFrameStalls[index] = 0
				}

				this.flvPlayers[index].on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
					console.warn(`Video ${index + 1} error:`, errorType, errorDetail, errorInfo)
					that.handleVideoError(index, errorType, errorDetail, errorInfo)
				})

				this.flvPlayers[index].on('statistics_info', function(res) {
					that.handleStatisticsInfo(index, res)
				})

				// 监听播放状态
				this.flvPlayers[index].on(flvjs.Events.LOADING_COMPLETE, () => {
					console.log(`Video ${index + 1} loading complete`)
					that.reconnectConfig.reconnectAttempts[index] = 0
					that.reconnectConfig.consecutiveFrameStalls[index] = 0
				})

				this.flvPlayers[index].on(flvjs.Events.MEDIA_INFO, () => {
					console.log(`Video ${index + 1} media info received`)
				})
			},

			handleVideoError(index, errorType, errorDetail, errorInfo) {
				// 如果是网络错误或解码错误，尝试重连
				if (errorType === flvjs.ErrorTypes.NETWORK_ERROR ||
					errorType === flvjs.ErrorTypes.MEDIA_ERROR) {
					this.smartReconnect(index, 'error')
				} else {
					console.warn(`Video ${index + 1} non-recoverable error:`, errorType)
				}
			},

			handleStatisticsInfo(index, res) {
				const now = Date.now()
				const lastCheckTime = this.reconnectConfig.lastFrameCheckTime[index] || 0

				// 只在指定间隔后检查帧数
				if (now - lastCheckTime < this.reconnectConfig.frameCheckInterval) {
					return
				}

				this.reconnectConfig.lastFrameCheckTime[index] = now

				if (this.lastDecodedFramesArr[index] === undefined) {
					this.lastDecodedFramesArr[index] = res.decodedFrames
					return
				}

				if (this.lastDecodedFramesArr[index] !== res.decodedFrames) {
					// 帧数正常更新
					this.lastDecodedFramesArr[index] = res.decodedFrames
					this.reconnectConfig.consecutiveFrameStalls[index] = 0
				} else {
					// 帧数停滞
					this.reconnectConfig.consecutiveFrameStalls[index]++

					// 连续停滞超过2次才考虑重连
					if (this.reconnectConfig.consecutiveFrameStalls[index] >= this.reconnectConfig
						.consecutiveFrameStallsThreshold) {
						console.warn(
							`Video ${index + 1} frame stall detected, consecutive: ${this.reconnectConfig.consecutiveFrameStalls[index]}`
						)
						this.smartReconnect(index, 'frame_stall')
					}
				}
			},

			smartReconnect(index, reason) {
				// 如果正在重连或超过最大重连次数，则不再重连
				if (this.reconnectConfig.isReconnecting[index] ||
					this.reconnectConfig.reconnectAttempts[index] >= this.reconnectConfig.maxReconnectAttempts) {
					console.warn(
						`Video ${index + 1} reconnect skipped: ${reason}, attempts: ${this.reconnectConfig.reconnectAttempts[index]}`
					)
					return
				}

				this.reconnectConfig.isReconnecting[index] = true
				this.reconnectConfig.reconnectAttempts[index]++

				// 使用指数退避算法计算重连延迟
				const delay = Math.min(
					this.reconnectConfig.baseDelay * Math.pow(2, this.reconnectConfig.reconnectAttempts[index] - 1),
					this.reconnectConfig.maxDelay
				)

				console.log(
					`Video ${index + 1} will reconnect in ${delay}ms, attempt ${this.reconnectConfig.reconnectAttempts[index]}`
				)

				// 清理之前的定时器
				if (this.reconnectConfig.reconnectTimers[index]) {
					clearTimeout(this.reconnectConfig.reconnectTimers[index])
				}

				this.reconnectConfig.reconnectTimers[index] = setTimeout(() => {
					this.performReconnect(index)
				}, delay)
			},

			performReconnect(index) {
				if (!this.lastVideoUrls[index]) {
					this.reconnectConfig.isReconnecting[index] = false
					return
				}

				// 检查网络状态
				if (!navigator.onLine) {
					console.warn(`Video ${index + 1} reconnect delayed: network offline`)
					this.reconnectConfig.isReconnecting[index] = false
					return
				}

				if (flvjs.isSupported()) {
					const videoElement = document.getElementById(index + 1)
					if (!videoElement) {
						this.reconnectConfig.isReconnecting[index] = false
						return
					}

					console.log(`Video ${index + 1} reconnecting...`)

					// 销毁旧的播放器
					this.destroyPlayer(index)

					// 创建新的播放器
					this.flvPlayers[index] = flvjs.createPlayer({
							type: 'flv',
							isLive: true,
							hasAudio: false,
							url: this.lastVideoUrls[index],
						},
						this.playerConfig,
					)

					this.flvPlayers[index].attachMediaElement(videoElement)
					this.flvPlayers[index].load()

					try {
						const playPromise = this.flvPlayers[index].play()
						if (playPromise && playPromise.catch) {
							playPromise.catch(e => {
								console.warn(`Video ${index + 1} play() error:`, e)
								this.reconnectConfig.isReconnecting[index] = false
							})
						}
					} catch (e) {
						console.warn(`Video ${index + 1} play() error:`, e)
						this.reconnectConfig.isReconnecting[index] = false
					}

					this.listenVideo(index)
				} else {
					this.reconnectConfig.isReconnecting[index] = false
				}
			},
			getChartData() {
				const {
					data,
					property
				} = this.config.config

				// 如果dataSourceType为静态数据,把数据放到Vuex，发出事件，然后退出
				if (data.dataSourceType === 'staticData') {
					this.showVisible = true
					// 重置数据异常状态
					this.resetAbnormalType()
					return
				}
			},

			checkNegative,
			itemClick(params, data) {
				console.log(params)
				this.chartClick(params, data)
				if (params) {
					this.sendAdvancedLinkagge({
						...params,
					})
				}
			},
			handleAsTooltip(filterRes) {
				const {
					property
				} = this.config.config
				const convertedData = convertData(filterRes, property)
				this.generateChart(convertedData)
			},
			handleNetworkChange(event) {
				const isOnline = event.type === 'online'
				console.log(`Network status changed: ${isOnline ? 'online' : 'offline'}`)

				if (isOnline) {
					// 网络恢复时，尝试重连所有断开的视频
					for (let i = 0; i < this.cellCount; i++) {
						if (this.lastVideoUrls[i] && !this.flvPlayers[i] && !this.reconnectConfig.isReconnecting[i]) {
							console.log(`Attempting to reconnect video ${i + 1} after network recovery`)
							this.reconnectConfig.reconnectAttempts[i] = 0 // 重置重连次数
							this.smartReconnect(i, 'network_recovery')
						}
					}
				} else {
					// 网络断开时，暂停所有重连尝试
					console.log('Network offline, pausing all reconnect attempts')
					this.reconnectConfig.reconnectTimers.forEach((timer, index) => {
						if (timer) {
							clearTimeout(timer)
							this.reconnectConfig.reconnectTimers[index] = null
							this.reconnectConfig.isReconnecting[index] = false
						}
					})
				}
			},
			startPerformanceMonitoring() {
				this.performanceConfig.monitorTimer = setInterval(() => {
					this.collectPerformanceStats()
				}, this.performanceConfig.monitorInterval)
			},

			collectPerformanceStats() {
				const stats = {
					timestamp: Date.now(),
					activePlayers: 0,
					reconnectingPlayers: 0,
					totalReconnectAttempts: 0,
					memoryUsage: null,
					networkStatus: navigator.onLine,
				}

				// 统计活跃播放器数量
				for (let i = 0; i < this.cellCount; i++) {
					if (this.flvPlayers[i]) {
						stats.activePlayers++
					}
					if (this.reconnectConfig.isReconnecting[i]) {
						stats.reconnectingPlayers++
					}
					stats.totalReconnectAttempts += this.reconnectConfig.reconnectAttempts[i] || 0
				}

				// 获取内存使用情况（如果支持）
				if (performance.memory) {
					stats.memoryUsage = {
						used: Math.round(performance.memory.usedJSHeapSize / 1024 / 1024),
						total: Math.round(performance.memory.totalJSHeapSize / 1024 / 1024),
						limit: Math.round(performance.memory.jsHeapSizeLimit / 1024 / 1024),
					}
				}

				this.performanceConfig.performanceStats.push(stats)

				// 只保留最近100条记录
				if (this.performanceConfig.performanceStats.length > this.performanceConfig.maxStatsRecords) {
					this.performanceConfig.performanceStats.shift()
				}

				// 如果内存使用过高，考虑清理一些播放器
				if (stats.memoryUsage && stats.memoryUsage.used > stats.memoryUsage.limit * this.performanceConfig
					.memoryWarningThreshold) {
					console.warn('High memory usage detected, consider reducing active players')
				}

				// 如果重连次数过多，输出警告
				if (stats.totalReconnectAttempts > this.cellCount * this.performanceConfig.reconnectWarningThreshold) {
					console.warn('High reconnect attempts detected, check network stability')
				}
			},

			getPerformanceStats() {
				return this.performanceConfig.performanceStats
			},
		},
	}
</script>
<style lang="less" scoped>
	// 图表通用样式，主要有黑色loading 和 黑色 '没有数据'，样式名需一致
	@import '../../common/chart.less';
</style>
<style>
	/* 全局loading样式修改 */

	.chartMain .loading .el-loading-spinner .circular {
		width: 34px !important;
		height: 34px !important;
	}

	.chartMain .el-dialog__header {
		padding: 9px 20px 10px !important;
		background: #2a3352 !important;
		text-align: left;
		box-sizing: border-box;
		height: 50px;
		line-height: 32px;
	}

	.chartMain .el-dialog__title {
		text-align: left;
		/* font-size: 18px; */
		line-height: 18px !important;
		color: #b2d3fe !important;
	}

	.chartMain .el-dialog__body {
		padding: 10px 20px 30px 20px;
		background: #1a2032 !important;
		line-height: 24px;
		font-size: 14px;
	}

	.chartMain .el-dialog__headerbtn .el-dialog__close {
		color: #b2d3fe !important;
	}

	.chartMain .dialog-footer {
		text-align: right;
		margin-bottom: -14px;
		margin-right: 4px;
	}

	.chartMain .el-dialog__headerbtn {
		top: 15px;
		/* font-size: 18px; */
	}
</style>
<style scoped lang="less">
	/deep/.el-select__wrapper {
		background-color: rgba(255, 255, 255, 0);
		box-shadow: 0 0 0 1px #0E4B6E !important;
	}

	.cell {
		width: 100%;
		height: 100%;
		position: absolute;
	}

	.cell-tool {
		height: 40px;
		line-height: 30px;
	}

	.videobox {
		width: 100%;
		height: 92%;
		background: url(./image/right.png) no-repeat;
		background-size: 100% 100%;
		position: absolute;
		left: 0;
		bottom: 0;
	}

	.cell-player {
		width: 95%;
		height: 90%;
		flex: 1;
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;
		padding: 5px;
		background: #000;
		position: absolute;
		left: 0;
		right: 0;
		top: 0;
		bottom: 0;
		margin: auto;
	}

	.cell-player-4 {
		width: 50%;
		height: 50% !important;
		box-sizing: border-box;
		padding: 5px;
		position: relative;

		.bottomtitle {
			width: 99%;
			height: 30px;
			position: absolute;
			left: 5px;
			bottom: 0;
		}

		video {
			width: 100%;
			/* 视频宽度填满容器 */
			height: 100%;
			/* 视频高度填满容器 */
			object-fit: cover;
			/* 保持视频的宽高比并覆盖整个容器 */
		}
	}

	.cell-player-1 {
		width: 100%;
		height: 100%;
		box-sizing: border-box;
		position: relative;

		.bottomtitle {
			width: 100%;
			height: 30px;
			position: absolute;
			left: 0;
			bottom: 0;
		}

		video {
			width: 100%;
			/* 视频宽度填满容器 */
			height: 100%;
			/* 视频高度填满容器 */
			object-fit: cover;
			/* 保持视频的宽高比并覆盖整个容器 */
		}
	}

	.cell-player-9 {
		width: 33.33%;
		height: 33.33% !important;
		box-sizing: border-box;
		padding: 5px;
		position: relative;

		.bottomtitle {
			width: 98%;
			height: 30px;
			position: absolute;
			left: 5px;
			bottom: 0;
		}

		video {
			width: 100%;
			/* 视频宽度填满容器 */
			height: 100%;
			/* 视频高度填满容器 */
			object-fit: cover;
			/* 保持视频的宽高比并覆盖整个容器 */
		}
	}

	.cell-player-16 {
		width: 25%;
		height: 25% !important;
		box-sizing: border-box;
		padding: 5px;
		position: relative;

		.bottomtitle {
			width: 97%;
			height: 30px;
			position: absolute;
			left: 5px;
			bottom: 0;
		}

		video {
			width: 100%;
			/* 视频宽度填满容器 */
			height: 100%;
			/* 视频高度填满容器 */
			object-fit: cover;
			/* 保持视频的宽高比并覆盖整个容器 */
		}
	}

	.cell {
		display: flex;
		flex-direction: column;
		height: 100%;
	}

	.bk-button-group {
		width: 100%;
		height: 30px;
		position: relative;
	}

	.btnSplitScreen {
		width: 310px;
		height: 28px;
		list-style: none;
		margin: 0;
		padding: 0;
		position: absolute;
		right: 0;
		top: 0;

		li {
			width: 28px;
			height: 28px;
			float: left;
			margin-right: 24px;
		}

		li:nth-child(6) {
			margin-right: 0;
		}
	}

	.active {
		background: url(./image/a.png) no-repeat;
		background-size: 100% 100%;
	}

	.inactive {
		background: url(./image/active.png) no-repeat;
		background-size: 100% 100%;
	}

	.factive {
		background: url(./image/f.png) no-repeat;
		background-size: 100% 100%;
	}

	.finactive {
		background: url(./image/factive.png) no-repeat;
		background-size: 100% 100%;
	}

	.nactive {
		background: url(./image/n.png);
		background-size: 100% 100%;
	}

	.ninactive {
		background: url(./image/nactive.png) no-repeat;
		background-size: 100% 100%;
	}

	.txactive {
		background: url(./image/tx.png) no-repeat;
		background-size: 100% 100%;
	}

	.txinactive {
		background: url(./image/txactive.png) no-repeat;
		background-size: 100% 100%;
	}

	.screen {
		background: url(./image/qps.png) no-repeat;
		background-size: 100% 100%;
	}

	.savescene {
		background: url(./image/cjbc.png) no-repeat;
		background-size: 100% 100%;
	}

	video::-webkit-media-controls-panel,
	video::-webkit-media-controls-loading-panel {
		display: none !important;
		opacity: 0 !important;
	}

	video::-webkit-media-controls-enclosure {
		overflow: hidden;
	}

	.cellvideo {
		position: relative;
	}

	.cancel {
		width: 28px;
		height: 28px;
		position: absolute;
		top: 15px;
		right: 40px;
	}

	.bottomtitle {
		span:nth-child(1) {
			display: inline-block;
			width: 28px;
			height: 18px;
			background: #ffa100;
			color: #1e3146;
			text-align: center;
			line-height: 18px;
			position: absolute;
			left: 12px;
			top: 7px;
			transform: skew(-30deg);
			/* 倾斜角度 */
			overflow: hidden;
			/* 防止内容溢出 */
		}

		span:nth-child(2) {
			display: inline-block;
			height: 30px;
			line-height: 30px;
			color: #fff;
			position: absolute;
			left: 50px;
			top: 0px;
		}

		span:nth-child(3) {
			display: inline-block;
			width: 28px;
			height: 28px;
			position: absolute;
			right: 12px;
			top: 1px;
		}
	}
</style>